<!DOCTYPE html>












  


<html class="theme-next muse use-motion" lang="zh-CN">
<head><meta name="generator" content="Hexo 3.8.0">
  <meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">












<meta http-equiv="Cache-Control" content="no-transform">
<meta http-equiv="Cache-Control" content="no-siteapp">






















<link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css">

<link href="/css/main.css?v=6.5.0" rel="stylesheet" type="text/css">


  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png?v=6.5.0">


  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png?v=6.5.0">


  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png?v=6.5.0">


  <link rel="mask-icon" href="/images/logo.svg?v=6.5.0" color="#222">









<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/',
    scheme: 'Muse',
    version: '6.5.0',
    sidebar: {"position":"left","display":"post","offset":12,"b2t":false,"scrollpercent":false,"onmobile":false},
    fancybox: false,
    fastclick: false,
    lazyload: false,
    tabs: true,
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>


  




  <meta name="description" content="在上一篇文章自定义用户认证逻辑中我演示了如何通过实现UserDetailsService接口来进行自定义的认证逻辑，包括数据从哪里取，包括定制用户是否锁定，是否冻结等状态信息。虽然只要我们愿意，现在数据已经可以从数据库中获取了，但是整个的认证流程仍不能满足我们的需要，我们在这一篇中进行进一步的用户认证个性化。">
<meta property="og:type" content="article">
<meta property="og:title" content="个性化用户认证流程(一)">
<meta property="og:url" content="https://lisb.gitee.io/2018/05/05/2018-05-05-个性化用户认证流程(一)/index.html">
<meta property="og:site_name" content="码畜·小布">
<meta property="og:description" content="在上一篇文章自定义用户认证逻辑中我演示了如何通过实现UserDetailsService接口来进行自定义的认证逻辑，包括数据从哪里取，包括定制用户是否锁定，是否冻结等状态信息。虽然只要我们愿意，现在数据已经可以从数据库中获取了，但是整个的认证流程仍不能满足我们的需要，我们在这一篇中进行进一步的用户认证个性化。">
<meta property="og:locale" content="zh-CN">
<meta property="og:image" content="http://p7sojn4oj.bkt.clouddn.com/201855104916.png">
<meta property="og:image" content="http://p7sojn4oj.bkt.clouddn.com/201855111247.png">
<meta property="og:updated_time" content="2018-05-05T03:37:08.243Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="个性化用户认证流程(一)">
<meta name="twitter:description" content="在上一篇文章自定义用户认证逻辑中我演示了如何通过实现UserDetailsService接口来进行自定义的认证逻辑，包括数据从哪里取，包括定制用户是否锁定，是否冻结等状态信息。虽然只要我们愿意，现在数据已经可以从数据库中获取了，但是整个的认证流程仍不能满足我们的需要，我们在这一篇中进行进一步的用户认证个性化。">
<meta name="twitter:image" content="http://p7sojn4oj.bkt.clouddn.com/201855104916.png">






  <link rel="canonical" href="https://lisb.gitee.io/2018/05/05/2018-05-05-个性化用户认证流程(一)/">



<script type="text/javascript" id="page.configurations">
  CONFIG.page = {
    sidebar: "",
  };
</script>

  <title>个性化用户认证流程(一) | 码畜·小布</title>
  











  <noscript>
  <style type="text/css">
    .use-motion .motion-element,
    .use-motion .brand,
    .use-motion .menu-item,
    .sidebar-inner,
    .use-motion .post-block,
    .use-motion .pagination,
    .use-motion .comments,
    .use-motion .post-header,
    .use-motion .post-body,
    .use-motion .collection-title { opacity: initial; }

    .use-motion .logo,
    .use-motion .site-title,
    .use-motion .site-subtitle {
      opacity: initial;
      top: initial;
    }

    .use-motion {
      .logo-line-before i { left: initial; }
      .logo-line-after i { right: initial; }
    }
  </style>
</noscript>

</head>

<body itemscope="" itemtype="http://schema.org/WebPage" lang="zh-CN">

  
  
    
  

  <div class="container sidebar-position-left page-post-detail">
    <div class="headband"></div>

    <header id="header" class="header" itemscope="" itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta ">
    

    <div class="custom-logo-site-title">
      <a href="/" class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">码畜·小布</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
    
  </div>

  <div class="site-nav-toggle">
    <button aria-label="切换导航栏">
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>



<nav class="site-nav">
  
    <ul id="menu" class="menu">
      
        
        
        
          
          <li class="menu-item menu-item-home">

    
    
    
      
    

    

    <a href="/" rel="section"><i class="menu-item-icon fa fa-fw fa-home"></i> <br>首页</a>

  </li>
        
        
        
          
          <li class="menu-item menu-item-archives">

    
    
    
      
    

    

    <a href="/archives/" rel="section"><i class="menu-item-icon fa fa-fw fa-archive"></i> <br>归档</a>

  </li>

      
      
    </ul>
  

  
    

  

  
</nav>



  



</div>
    </header>

    


    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  

  
  
  

  

  <article class="post post-type-normal" itemscope="" itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="https://lisb.gitee.io/2018/05/05/2018-05-05-个性化用户认证流程(一)/">

    <span hidden itemprop="author" itemscope="" itemtype="http://schema.org/Person">
      <meta itemprop="name" content="小布">
      <meta itemprop="description" content="曾梦想仗剑走天涯，后来bug太多就没去">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope="" itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="码畜·小布">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">个性化用户认证流程(一)
              
            
          </h1>
        

        <div class="post-meta">
          <span class="post-time">

            
            
            

            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              

              
                
              

              <time title="创建时间：2018-05-05 10:13:15 / 修改时间：11:37:08" itemprop="dateCreated datePublished" datetime="2018-05-05T10:13:15+08:00">2018-05-05</time>
            

            
              

              
            
          </span>

          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        <p>在上一篇文章<a href="https://lishangbu.github.io/posts/%E8%87%AA%E5%AE%9A%E4%B9%89%E7%94%A8%E6%88%B7%E8%AE%A4%E8%AF%81%E9%80%BB%E8%BE%91/" target="_blank" rel="noopener">自定义用户认证逻辑</a>中我演示了如何通过实现UserDetailsService接口来进行自定义的认证逻辑，包括数据从哪里取，包括定制用户是否锁定，是否冻结等状态信息。虽然只要我们愿意，现在数据已经可以从数据库中获取了，但是整个的认证流程仍不能满足我们的需要，我们在这一篇中进行进一步的用户认证个性化。<br><a id="more"></a><br>在上一篇的文章结束后，我们可以显著地发现，我们的这套认证流程中还存在着以下的问题：</p>
<ul>
<li>自定义登录页面。我们之前使用的登录页面都是由Spring Security自动生成的，在实际的项目中我们肯定不会使用这个登录页面，而是使用自定义的登录页面。</li>
<li>自定义登录成功处理。目前这个登录成功的时候，它的一个默认的处理机制是跳转到了你之前请求的URL上，但是我们实际项目中登录成功后肯定希望可以有额外的一些操作，比如说每日签到做个记录什么的，这个动作怎么来做，怎么来写代码？实际上，这个动作就是在登录成功处理器这里处理的。下文我们会具体地讲一下。</li>
<li>自定义登录失败处理。如果说用户登录失败了，比如说用户密码输错了，我们现在一个默认的处理逻辑是显示一个错误信息，但是实际情况中，碰到这种情况我们可能还会想去记录一下错误日志，比如说它今天已经出错的次数，比如说有个需求就是错了三次以后今天就不允许他再登录了，等等这些逻辑就是在登录失败处理器这里处理的，下文我们来看一下如何进行这种登录失败的自定义处理。</li>
</ul>
<h1 id="自定义登录页面"><a href="#自定义登录页面" class="headerlink" title="自定义登录页面"></a>自定义登录页面</h1><p>要想自定义登录页面，我们打开上一章节的工程，在WebSecurityConfig配置类的configure方法的formLogin后面加一句配置：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">configure</span><span class="params">(HttpSecurity http)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">	<span class="comment">//启用基于表单形式的登录</span></span><br><span class="line">	http.formLogin()</span><br><span class="line">			<span class="comment">//自定义登录页</span></span><br><span class="line">			.loginPage(<span class="string">"/login.html"</span>)</span><br><span class="line">			.and()</span><br><span class="line">			<span class="comment">//下面的配置都是关于授权的配置</span></span><br><span class="line">			.authorizeRequests()</span><br><span class="line">			<span class="comment">//任何请求</span></span><br><span class="line">			.anyRequest()</span><br><span class="line">			<span class="comment">//都需要认证</span></span><br><span class="line">			.authenticated();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>loginPage的作用就是指定我们的登录页面所在的URL，现在登录的时候它就会去找这个”login.html”的页面，我们现在把这个自定义的页面也写一下,在工程的resources文件夹下新建一个static文件夹，然后在static文件夹下我们来写一个login.html的登录页面，代码如下：<br><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE html&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">"en"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"UTF-8"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>登录<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">h1</span>&gt;</span>演示登录页面<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<p>具体的需要提交的表单元素我们先不进行填写，我们先启动一下工程，看看现在的效果。<br>启动工程后，我们还是访问“/hello”这个接口，我们会看到浏览器会出现下方的提示:   </p>
<p><img src="http://p7sojn4oj.bkt.clouddn.com/201855104916.png" alt="201855104916"></p>
<p>浏览器提示了一个错误信息：localhost 将您重定向的次数过多。这个是他在跳转到”/login.html”的时候报出来的错误，为什么会这样呢？<br>观察之前的安全配置类，我们很容易就能找到原因。这是因为，我们配置了一个登录页面，但是下面的请求却写着所有的请求都需要认证。于是就陷入了以下的逻辑：  </p>
<p>我们访问“/hello”接口-&gt;<br><figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">├── 我们访问<span class="string">"/hello"</span>接口,框架发现<span class="string">"/hello"</span>接口需要认证，当前用户还未认证，跳转到自定义的登录页面<span class="string">"/login.html"</span></span><br><span class="line">│</span><br><span class="line">├── 框架试图跳转到<span class="string">"/login.html"</span>发现<span class="string">"/login.html"</span>也需要认证，当前用户还未认证，跳转到自身页面<span class="string">"/login.html"</span></span><br><span class="line">│</span><br><span class="line">├── 框架再次试图跳转到<span class="string">"/login.html"</span>发现<span class="string">"/login.html"</span>也需要认证，当前用户还未认证，跳转到自身页面<span class="string">"/login.html"</span></span><br><span class="line">│</span><br><span class="line">├── ……</span><br></pre></td></tr></table></figure></p>
<p>于是最终就这么死循环下去了,这也是刚开始使用Spring Security的人最常犯的一个错误,他们经常加一些自己的页面或者服务进去但是忘了配置授权，这样的话实际上这些页面和服务别人是调用不到的。想要处理这个问题也很简单，我们只需要在授权的页面上加一个配置，放行登录页即可。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">configure</span><span class="params">(HttpSecurity http)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">	<span class="comment">//启用基于表单形式的登录</span></span><br><span class="line">	http.formLogin()</span><br><span class="line">			<span class="comment">//自定义登录页</span></span><br><span class="line">			.loginPage(<span class="string">"/login.html"</span>)</span><br><span class="line">			.and()</span><br><span class="line">			<span class="comment">//下面的配置都是关于授权的配置</span></span><br><span class="line">			.authorizeRequests()</span><br><span class="line">			<span class="comment">//放行登录页</span></span><br><span class="line">			.antMatchers(<span class="string">"/login.html"</span>)</span><br><span class="line">			.permitAll()</span><br><span class="line">			<span class="comment">//任何请求</span></span><br><span class="line">			.anyRequest()</span><br><span class="line">			<span class="comment">//都需要认证</span></span><br><span class="line">			.authenticated();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>“antMatchers(“/login.html”).permitAll()”这句话的意思就是说，当访问“/login.html”的时候，我们不需要身份认证就可以访问。它和下面的”                anyRequest().authenticated()”结合起来的意思就是说，除了这个配置以外，其他的请求都需要身份认证,加了这句配置以后我们重新启动一下我们的工程，再去访问”/hello”服务，我们就可以看到，已经成功地跳转到登录页面了。</p>
<p><img src="http://p7sojn4oj.bkt.clouddn.com/201855111247.png" alt="201855111247"></p>
<p>然后我们来完善一下这个表单登录页面，代码如下：<br><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE html&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">"en"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"UTF-8"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>登录<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">h1</span>&gt;</span>演示登录页面<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">h4</span>&gt;</span>表单登录<span class="tag">&lt;/<span class="name">h4</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">form</span> <span class="attr">action</span>=<span class="string">"/authentication/form"</span> <span class="attr">method</span>=<span class="string">"post"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">table</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">tr</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">td</span>&gt;</span>用户名：<span class="tag">&lt;/<span class="name">td</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">td</span>&gt;</span><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">name</span>=<span class="string">"username"</span> /&gt;</span><span class="tag">&lt;/<span class="name">td</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">tr</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">tr</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">td</span>&gt;</span>密码：<span class="tag">&lt;/<span class="name">td</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">td</span>&gt;</span><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"password"</span> <span class="attr">name</span>=<span class="string">"password"</span> /&gt;</span><span class="tag">&lt;/<span class="name">td</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">tr</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">tr</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">td</span> <span class="attr">colspan</span>=<span class="string">"2"</span>&gt;</span><span class="tag">&lt;<span class="name">button</span> <span class="attr">type</span>=<span class="string">"submit"</span> <span class="attr">value</span>=<span class="string">"登录"</span>/&gt;</span><span class="tag">&lt;/<span class="name">td</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">tr</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">table</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<p>其中，表单提交的路径”/authentication/form”是由我们自己定义的，在<a href="https://lishangbu.github.io/posts/Spring-Security基本原理/" target="_blank" rel="noopener">Spring Security基本原理</a>这篇文章中我们讲过表单登录实际上是由UsernamePasswordAuthenticationFilter这个过滤器来处理的，这个过滤器的源码如下：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">UsernamePasswordAuthenticationFilter</span> <span class="keyword">extends</span></span></span><br><span class="line"><span class="class">		<span class="title">AbstractAuthenticationProcessingFilter</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String SPRING_SECURITY_FORM_USERNAME_KEY = <span class="string">"username"</span>;</span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String SPRING_SECURITY_FORM_PASSWORD_KEY = <span class="string">"password"</span>;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">private</span> String usernameParameter = SPRING_SECURITY_FORM_USERNAME_KEY;</span><br><span class="line">	<span class="keyword">private</span> String passwordParameter = SPRING_SECURITY_FORM_PASSWORD_KEY;</span><br><span class="line">	<span class="keyword">private</span> <span class="keyword">boolean</span> postOnly = <span class="keyword">true</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="title">UsernamePasswordAuthenticationFilter</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		<span class="keyword">super</span>(<span class="keyword">new</span> AntPathRequestMatcher(<span class="string">"/login"</span>, <span class="string">"POST"</span>));</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">public</span> Authentication <span class="title">attemptAuthentication</span><span class="params">(HttpServletRequest request,</span></span></span><br><span class="line"><span class="function"><span class="params">			HttpServletResponse response)</span> <span class="keyword">throws</span> AuthenticationException </span>&#123;</span><br><span class="line">		<span class="keyword">if</span> (postOnly &amp;&amp; !request.getMethod().equals(<span class="string">"POST"</span>)) &#123;</span><br><span class="line">			<span class="keyword">throw</span> <span class="keyword">new</span> AuthenticationServiceException(</span><br><span class="line">					<span class="string">"Authentication method not supported: "</span> + request.getMethod());</span><br><span class="line">		&#125;</span><br><span class="line"></span><br><span class="line">		String username = obtainUsername(request);</span><br><span class="line">		String password = obtainPassword(request);</span><br><span class="line"></span><br><span class="line">		<span class="keyword">if</span> (username == <span class="keyword">null</span>) &#123;</span><br><span class="line">			username = <span class="string">""</span>;</span><br><span class="line">		&#125;</span><br><span class="line"></span><br><span class="line">		<span class="keyword">if</span> (password == <span class="keyword">null</span>) &#123;</span><br><span class="line">			password = <span class="string">""</span>;</span><br><span class="line">		&#125;</span><br><span class="line"></span><br><span class="line">		username = username.trim();</span><br><span class="line"></span><br><span class="line">		UsernamePasswordAuthenticationToken authRequest = <span class="keyword">new</span> UsernamePasswordAuthenticationToken(</span><br><span class="line">				username, password);</span><br><span class="line"></span><br><span class="line">		<span class="comment">// Allow subclasses to set the "details" property</span></span><br><span class="line">		setDetails(request, authRequest);</span><br><span class="line"></span><br><span class="line">		<span class="keyword">return</span> <span class="keyword">this</span>.getAuthenticationManager().authenticate(authRequest);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">protected</span> String <span class="title">obtainPassword</span><span class="params">(HttpServletRequest request)</span> </span>&#123;</span><br><span class="line">		<span class="keyword">return</span> request.getParameter(passwordParameter);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">protected</span> String <span class="title">obtainUsername</span><span class="params">(HttpServletRequest request)</span> </span>&#123;</span><br><span class="line">		<span class="keyword">return</span> request.getParameter(usernameParameter);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">setDetails</span><span class="params">(HttpServletRequest request,</span></span></span><br><span class="line"><span class="function"><span class="params">			UsernamePasswordAuthenticationToken authRequest)</span> </span>&#123;</span><br><span class="line">		authRequest.setDetails(authenticationDetailsSource.buildDetails(request));</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setUsernameParameter</span><span class="params">(String usernameParameter)</span> </span>&#123;</span><br><span class="line">		Assert.hasText(usernameParameter, <span class="string">"Username parameter must not be empty or null"</span>);</span><br><span class="line">		<span class="keyword">this</span>.usernameParameter = usernameParameter;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setPasswordParameter</span><span class="params">(String passwordParameter)</span> </span>&#123;</span><br><span class="line">		Assert.hasText(passwordParameter, <span class="string">"Password parameter must not be empty or null"</span>);</span><br><span class="line">		<span class="keyword">this</span>.passwordParameter = passwordParameter;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setPostOnly</span><span class="params">(<span class="keyword">boolean</span> postOnly)</span> </span>&#123;</span><br><span class="line">		<span class="keyword">this</span>.postOnly = postOnly;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">final</span> String <span class="title">getUsernameParameter</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		<span class="keyword">return</span> usernameParameter;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">final</span> String <span class="title">getPasswordParameter</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		<span class="keyword">return</span> passwordParameter;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>通过上面的代码，我们可以看到，这个过滤器默认处理的登录请求是POST方式的“/login”，接收的用户名和密码参数是username和password,可以看到，处理登录请求的URL和我们定义在表单中的不一样，为了让Spring Security知道我们希望让UsernamePasswordAuthenticationFilter这个过滤器去处理“/authentication/form”这个路径,我么在安全配置类里面加一个配置：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">configure</span><span class="params">(HttpSecurity http)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">	<span class="comment">//启用基于表单形式的登录</span></span><br><span class="line">	http.formLogin()</span><br><span class="line">			<span class="comment">//自定义登录页</span></span><br><span class="line">			.loginPage(<span class="string">"/login.html"</span>)</span><br><span class="line">			<span class="comment">//自定义登录请求路径</span></span><br><span class="line">			.loginProcessingUrl(<span class="string">"/authentication/form"</span>)</span><br><span class="line">			.and()</span><br><span class="line">			<span class="comment">//下面的配置都是关于授权的配置</span></span><br><span class="line">			.authorizeRequests()</span><br><span class="line">			<span class="comment">//放行登录页</span></span><br><span class="line">			.antMatchers(<span class="string">"/login.html"</span>)</span><br><span class="line">			.permitAll()</span><br><span class="line">			<span class="comment">//任何请求</span></span><br><span class="line">			.anyRequest()</span><br><span class="line">			<span class="comment">//都需要认证</span></span><br><span class="line">			.authenticated();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>这样，当我们提交这个“/authentication/form”请求的时候，Spring Security就知道，它要让UsernamePasswordAuthenticationFilter去处理这个请求,在这个请求里它会去获取用户名和密码来完成登录。然后我们启动一下应用。</p>

      
    </div>

    

    
    
    

    

    
       
    
    

    

    <footer class="post-footer">
      

      
      
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/2018/04/20/2018-04-20-自定义用户认证逻辑/" rel="next" title="自定义用户认证逻辑">
                <i class="fa fa-chevron-left"></i> 自定义用户认证逻辑
              </a>
            
          </div>

          <span class="post-nav-divider"></span>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/2018/05/15/2018-05-15-spring security oauth2 使用redis存token时报错/" rel="prev" title="Spring Security Oauth2 使用RedisTokenStore出错">
                Spring Security Oauth2 使用RedisTokenStore出错 <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </div>
  
  
  
  </article>


  </div>


          </div>
          

  



        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    
    <div class="sidebar-inner">

      

      
        <ul class="sidebar-nav motion-element">
          <li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap">
            文章目录
          </li>
          <li class="sidebar-nav-overview" data-target="site-overview-wrap">
            站点概览
          </li>
        </ul>
      

      <section class="site-overview-wrap sidebar-panel">
        <div class="site-overview">
          <div class="site-author motion-element" itemprop="author" itemscope="" itemtype="http://schema.org/Person">
            
              <p class="site-author-name" itemprop="name">小布</p>
              <p class="site-description motion-element" itemprop="description">曾梦想仗剑走天涯，后来bug太多就没去</p>
          </div>

          
            <nav class="site-state motion-element">
              
                <div class="site-state-item site-state-posts">
                
                  <a href="/archives/">
                
                    <span class="site-state-item-count">5</span>
                    <span class="site-state-item-name">日志</span>
                  </a>
                </div>
              

              

              
                
                
                <div class="site-state-item site-state-tags">
                  
                    
                    
                      
                    
                      
                    
                      
                    
                    <span class="site-state-item-count">3</span>
                    <span class="site-state-item-name">标签</span>
                  
                </div>
              
            </nav>
          

          

          

          

          
          

          
            
          
          

        </div>
      </section>

      
      <!--noindex-->
        <section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active">
          <div class="post-toc">

            
              
            

            
              <div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#自定义登录页面"><span class="nav-number">1.</span> <span class="nav-text">自定义登录页面</span></a></li></ol></div>
            

          </div>
        </section>
      <!--/noindex-->
      

      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright">&copy; <span itemprop="copyrightYear">2018</span>
  <span class="with-love" id="animate">
    <i class="fa fa-user"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">小布</span>

  

  
</div>


  <div class="powered-by">由 <a href="https://hexo.io" class="theme-link" rel="noopener" target="_blank">Hexo</a> 强力驱动 v3.8.0</div>



  <span class="post-meta-divider">|</span>



  <div class="theme-info">主题 – <a href="https://theme-next.org" class="theme-link" rel="noopener" target="_blank">NexT.Muse</a> v6.5.0</div>




        








        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    

    
	
    

    
  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>


























  
  
    <script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script>
  

  
  
    <script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>
  


  


  <script type="text/javascript" src="/js/src/utils.js?v=6.5.0"></script>

  <script type="text/javascript" src="/js/src/motion.js?v=6.5.0"></script>



  
  

  
  <script type="text/javascript" src="/js/src/scrollspy.js?v=6.5.0"></script>
<script type="text/javascript" src="/js/src/post-details.js?v=6.5.0"></script>



  


  <script type="text/javascript" src="/js/src/bootstrap.js?v=6.5.0"></script>



  



  










  





  

  

  

  

  

  
  

  

  

  

  

  

  

</body>
</html>
